<template>
  <div ref="GykjMap" class="GykjMap">
    <!-- 地图容器 -->
    <div ref="map" class="GykjMap-wrapper"></div>

    <!-- 切换底图工具 -->
    <div
      v-if="isNeedChosen && arcgisIndex > 1"
      class="GykjMap-chosen"
      :class="chosenClass">
      <ul
        ref="chosenList"
        class="chosen_list"
        @mouseenter="chosenListEnter"
        @mouseleave="chosenListLeave">
        <li
          v-if="!isHideBase"
          class="chosen_detail base"
          :class="{'active': active === 'base'}"
          @click="layerChosen('base')">
          <span>平面图</span>
        </li>
        <li
          v-if="!isHideTerrain"
          class="chosen_detail terrain"
          :class="{'active': active === 'terrain'}"
          @click="layerChosen('terrain')">
          <span>地形图</span>
        </li>
        <li
          v-if="!isHideSatellite"
          class="chosen_detail satellite"
          :class="{'active': active === 'satellite'}"
          @click="layerChosen('satellite')">
          <span>卫星图</span>
        </li>
      </ul>
    </div>

    <!-- loading -->
    <div class="GykjMap-loading" v-show="loading">
      <slot v-if="$slots.loading" name="loading"></slot>
      <Loading v-else></Loading>
    </div>
  </div>
</template>

<script>
// import Vue from 'vue'
import * as Maps from '../../map'
import * as Utils from '../../util'
import * as Commons from '../../common'
import * as Controls from '../../control'
import Loading from '../../public/loading/loading'

const { ERR_OK } = Utils
const layerError = '加载图层失败'

export default {
  props: {
    layerActive: {
      type: String,
      default: 'base'
    },
    defaultLayers: {
      type: Array,
      default: () => []
    },
    isHideBase: {
      type: Boolean,
      default: false
    },
    isHideTerrain: {
      type: Boolean,
      default: false
    },
    isHideSatellite: {
      type: Boolean,
      default: false
    },
    isNeedWaterNet: {
      type: Boolean,
      default: true
    },
    isNeedRoadNet: {
      type: Boolean,
      default: true
    },
    isNeedClick: {
      type: Boolean,
      default: true
    },
    isNeedSizeChange: {
      type: Boolean,
      default: true
    },
    isNeedShowModal: {
      type: Boolean,
      default: true
    },
    isNeedScaleLine: {
      type: Boolean,
      default: false
    },
    isNeedChosen: {
      type: Boolean,
      default: true
    },
    chosenClass: {
      type: String,
      default: ''
    }
  },
  components: {
    Loading
  },
  created () {
    this.init()
  },
  mounted () {
    setTimeout(() => {
      this.initChosen()
      this.initMap()
    }, 20)
  },
  data () {
    return {
      loading: false,
      Map: null,
      showIng: {},
      layers: {},
      active: ''
    }
  },
  methods: {
    getMap () {
      return this.Map
    },
    getLayers () {
      return this.layers
    },
    refreshAnimate ({ layerName }) {
      if (!layerName || !this.layers[layerName]) {
        return
      }

      this.layers[layerName].refreshAnimate()
    },
    addDraw (options = {}) {
      if (!this.showIng['drawUtilLayer']) {
        console.log('要先加入绘制工具图层')
        return
      }
      const { type } = options
      const typeArr = ['Point', 'LineString', 'Polygon', 'Circle', 'Square', 'Box']

      if (typeArr.indexOf(type) === -1) {
        console.log('绘制类型不正确')
        return
      }

      this.layers['drawUtilLayer'].addDraw({ type })
    },
    editDraw () {
      if (!this.showIng['drawUtilLayer']) {
        console.log('要先加入绘制工具图层')
        return
      }

      this.layers['drawUtilLayer'].editDraw()
    },
    deleteDraw () {
      if (!this.showIng['drawUtilLayer']) {
        console.log('要先加入绘制工具图层')
        return
      }

      this.layers['drawUtilLayer'].deleteDraw()
    },
    deleteAllDraw () {
      if (!this.showIng['drawUtilLayer']) {
        console.log('要先加入绘制工具图层')
        return
      }

      this.layers['drawUtilLayer'].deleteAllDraw()
    },
    removeDrawUtil () {
      if (!this.showIng['drawUtilLayer']) {
        console.log('要先加入绘制工具图层')
        return
      }

      this.layers['drawUtilLayer'].removeDrawUtil()
    },
    getDrawLayerGeoJson () {
      if (!this.showIng['drawUtilLayer']) {
        console.log('要先加入绘制工具图层')
        return
      }

      const geoJson = this.layers['drawUtilLayer'].getDrawLayerGeoJson()

      return geoJson
    },
    addCustomLayer (layer) {
      if (!layer) {
        Commons._showError('addCustomLayer 需要你传入一个 layer')
        return
      }

      this.Map.addLayer(layer)
    },
    addLayer (res) {
      if (!res) {
        Commons._showError('addLayer方法需要你传入正确的参数，且该参数为一个Object')
        return
      }

      if (this.loading) {
        return
      }

      const { layerName, layerOptions = {} } = res

      if (this.showIng[layerName]) {
        return
      }

      switch (layerName) {
        case 'waterNetLayer':
          if (this.isNeedWaterNet) {
            this.layers['GdWaterNetLayer'].setVisible(true)
            this.layers['HnWaterNetLayer'].setVisible(true)
            this.showIng[layerName] = true
          } else {
            Commons._showError('增加水网图层，isNeedWaterNet 参数不能为false')
          }
          break
        case 'roadNetLayer':
          if (this.isNeedRoadNet) {
            this.layers['roadNetLayer'].setVisible(true)
            this.showIng[layerName] = true
          } else {
            Commons._showError('增加路网图层，isNeedRoadNet 参数不能为false')
          }
          break
        case 'weatherWarningLayer':
          return (async () => {
            this.loading = true
            const res = await Maps.weatherWarningLayer({ layerOptions })
            this.loading = false
            if (res.code === ERR_OK) {
              this.$set(this.layers, layerName, res)
              this.addOverlayer(res.overLayerArr)
              this.showIng[layerName] = true
            } else {
              Commons._showErrorMessage(layerError)
            }
          })()
        case 'typhoonLayer':
          return (async () => {
            this.loading = true

            // this.$set(this.layers, 'typhoonList', {})
            const res = await Maps[layerName]({
              layerOptions: {
                ...layerOptions,
                Map: this.Map,
                Layers: this.layers,
                Dom: this.$refs['GykjMap']
              }
            })

            this.loading = false

            if (res.code === ERR_OK) {
              // this.$set(this.layers, 'typhoonList', {})
              this.$set(this.layers, layerName, res)
              this.showIng[layerName] = true
            } else {
              Commons._showErrorMessage(layerError)
            }
          })()
        case 'cloudLayer':
        case 'radarLayer':
          return (async () => {
            this.loading = true

            const res = await Maps[layerName]({
              layerOptions: {
                ...layerOptions,
                Map: this.Map,
                Layers: this.layers,
                Dom: this.$refs['GykjMap']
              }
            })

            this.loading = false

            if (res.code === ERR_OK) {
              this.$set(this.layers, res.layerName, res)
              this.showIng[layerName] = true
            } else {
              Commons._showErrorMessage(layerError)
            }
          })()
        case 'banksLayer':
        case 'criticalsLayer':
          const res = Maps[layerName]({ layerOptions })
          this.addLayerAndOverlay(res)
          this.showIng[layerName] = true
          break
        case 'gateLayer':
        case 'pumpLayer':
        case 'reservoirLayer':
        case 'waterLoggingCityLayer':
          return (async () => {
            this.loading = true
            const res = await Maps[layerName]({ layerOptions })
            this.loading = false
            if (res.code === ERR_OK) {
              this.addLayerAndOverlay(res)
              Utils.isShowOverLayer(this.Map, res.hideClass)
              this.showIng[layerName] = true
            } else {
              Commons._showErrorMessage(layerError)
            }
          })()
        case 'waterLevelLayer':
        case 'hydrologyLayer':
        case 'tideGaugeLayer':
          return (async () => {
            this.loading = true
            const res = await Maps[layerName]({ layerOptions })
            this.loading = false
            if (res.code === ERR_OK) {
              this.addLayerAndOverlay(res)
              this.showIng[layerName] = true
            } else {
              Commons._showErrorMessage(layerError)
            }
          })()
        case 'drainPortLayer':
        case 'ironhideHouseLayer':
        case 'barrackLayer':
        case 'otherBuildLayer':
          return (async () => {
            this.loading = true
            const res = await Maps[layerName]({
              layerOptions: {
                ...layerOptions,
                Map: this.Map
              }
            })
            this.loading = false
            if (res.code === ERR_OK) {
              this.addLayerAndOverlay(res)
              this.showIng[layerName] = true
            } else {
              Commons._showErrorMessage(layerError)
            }
          })()
        case 'drawUtilLayer':
          return (() => {
            const res = Maps[layerName]({
              layerOptions: {
                ...layerOptions,
                Map: this.Map
              }
            })

            this.addLayerAndOverlay(res)
            this.showIng[layerName] = true
          })()
        default:
          return (async () => {
            this.loading = true
            const res = await Maps[layerName]({ layerOptions })
            this.loading = false
            if (res.code === ERR_OK) {
              this.addLayerAndOverlay(res)
              Utils.isShowOverLayer(this.Map, res.hideClass)
              this.showIng[layerName] = true
            } else {
              Commons._showErrorMessage(layerError)
            }
          })()
      }
    },
    addOverlayer (overlay) {
      if (!overlay) {
        Commons._showError('addOverlayer方法需要你传入一个overlay或[overlay]')
        return
      }

      if (Array.isArray(overlay)) {
        overlay.map(item => {
          this.Map.addOverlay(item)
        })
      } else {
        this.Map.addOverlay(overlay)
      }
    },
    addLayerAndOverlay (res) {
      const { layerName, layer, overLayerArr } = res
      this.$set(this.layers, layerName, res)

      if (layer) {
        this.Map.addLayer(layer)
      }

      if (overLayerArr) {
        overLayerArr.map(item => {
          this.Map.addOverlay(item)
        })
      }
    },
    removeCustomLayer (layer) {
      if (!layer) {
        Commons._showError('removeCustomLayer 需要你传入一个 layer')
        return
      }

      this.Map.removeLayer(layer)
    },
    removeLayer (res) {
      if (!res) {
        Commons._showError('removeLayer方法需要你传入正确的参数，且该参数为一个Object')
        return
      }

      const { layerName } = res

      if (!this.showIng[layerName]) {
        return
      }

      switch (layerName) {
        case 'waterNetLayer':
          if (this.isNeedWaterNet) {
            this.layers['GdWaterNetLayer'].setVisible(false)
            this.layers['HnWaterNetLayer'].setVisible(false)
            this.showIng[layerName] = false
          } else {
            Commons._showError('删除水网图层，isNeedWaterNet 参数不能为false')
          }
          break
        case 'roadNetLayer':
          if (this.isNeedRoadNet) {
            this.layers['roadNetLayer'].setVisible(false)
            this.showIng[layerName] = false
          } else {
            Commons._showError('删除路网图层，isNeedRoadNet 参数不能为false')
          }
          break
        case 'weatherWarningLayer':
          this.removeOverlayer(this.layers['weatherWarningLayer'].overLayerArr)
          this.$delete(this.layers, layerName)
          this.showIng[layerName] = false
          break
        case 'typhoonLayer':
          for (let key in this.layers['typhoonList']) {
            clearInterval(this.layers['typhoonList'][key].interval)
            this.Map.removeLayer(this.layers['typhoonList'][key]['layer'])
            this.Map.removeOverlay(this.layers['typhoonList'][key]['typhoon']['typhoonStrong'])
          }
          this.layers[layerName].hideInfo()

          this.$delete(this.layers, layerName)
          this.$delete(this.layers, 'typhoonList')
          this.showIng[layerName] = false
          break
        case 'cloudLayer':
        case 'radarLayer':
          clearInterval(this.layers[layerName].timeInterval)
          this.Map.removeLayer(this.layers[layerName].layer)
          this.$delete(this.layers, layerName)
          this.showIng[layerName] = false
          break
        case 'banksLayer':
        case 'criticalsLayer':
        case 'gateLayer':
        case 'pumpLayer':
        case 'waterLevelLayer':
        case 'hydrologyLayer':
        case 'tideGaugeLayer':
        case 'reservoirLayer':
        case 'waterLoggingCityLayer':
          this.removeLayerAndOverlay(this.layers[layerName])
          this.showIng[layerName] = false
          break
        case 'drawUtilLayer':
          this.layers[layerName].removeDrawUtil()
          this.removeLayerAndOverlay(this.layers[layerName])
          this.showIng[layerName] = false
          break
        default :
          this.removeLayerAndOverlay(this.layers[layerName])
          this.$delete(this.layers, layerName)
          this.showIng[layerName] = false
          break
      }
    },
    removeOverlayer (overlay) {
      if (!overlay) {
        Commons._showError('removeOverlayer方法需要你传入一个overlay或[overlay]')
        return
      }

      if (Array.isArray(overlay)) {
        overlay.map(item => {
          this.Map.removeOverlay(item)
        })
      } else {
        this.Map.removeOverlay(overlay)
      }
    },
    removeLayerAndOverlay (res) {
      const { layerName, layer, overLayerArr } = res

      if (layer) {
        this.Map.removeLayer(layer)
      }

      if (overLayerArr) {
        overLayerArr.map(item => {
          this.Map.removeOverlay(item)
        })
      }

      this.$delete(this.layers, layerName)
    },
    chosenListEnter () {
      this.refChosenList.style.width = `${this.arcgisIndex * 92}px`

      let index = 0
      for (let i = this.arcgisIndex; i >= 0; i--) {
        if (i - 2 >= 0) {
          this.refChosenListChild[i - 2].style.right = `${index * 90 + 98}px`
          index += 1
        }
      }
    },
    chosenListLeave () {
      this.refChosenList.style.width = ''
      this.initChosen()
    },
    layerChosen (name, isInit) {
      if (name === this.active && !isInit) {
        return
      }

      let obj = {}
      switch (name) {
        case 'base':
          obj = {
            base: true,
            terrain: false,
            satellite: false
          }
          break
        case 'terrain':
          obj = {
            base: false,
            terrain: true,
            satellite: false
          }
          break
        case 'satellite':
          obj = {
            base: false,
            terrain: false,
            satellite: true
          }
          break
      }

      if (!this.isHideBase) {
        this.layers['baseLayer'].setVisible(obj.base)
      }
      if (!this.isHideTerrain) {
        this.layers['terrainLayer'].setVisible(obj.terrain)
      }
      if (!this.isHideSatellite) {
        this.layers['GdSatelliteLayer'].setVisible(obj.satellite)
        this.layers['FsSatelliteLayer'].setVisible(obj.satellite)
      }

      this.active = name
    },
    initChosen () {
      if (!this.isNeedChosen) {
        return
      }

      if (this.arcgisIndex <= 1) {
        return
      }

      this.refChosenList = this.$refs['chosenList']

      if (!this.refChosenList) {
        return
      }

      this.refChosenListChild = this.refChosenList.children

      this.refChosenList.style.width = `${(this.arcgisIndex - 1) * 11 + 96}px`

      let index = 0
      for (let i = this.refChosenListChild.length - 1; i >= 0; i--) {
        const element = this.refChosenListChild[i]

        element.style.right = `${index * 10 + 8}px`
        index += 1
      }
    },
    initMap () {
      const mapOption = {
        el: this.$refs['map'],
        layers: [...this.arcgisLayers, ...this.defaultLayers]
      }

      if (this.isNeedScaleLine) {
        mapOption.controls = Controls.createScaleLine()
      }

      this.Map = Maps.createMap(mapOption)

      if (this.isNeedClick) {
        this.Map.on('singleclick', (event) => {
          const pixel = event.pixel
          const lng = event.coordinate[0]
          const lat = event.coordinate[1]
          const features = []
          const layerNames = []

          this.Map.forEachFeatureAtPixel(pixel, (feature, layer) => {
            features.push(feature)
            if (layer) {
              layerNames.push(layer.get('name') === null ? '' : layer.get('name'))
            }
          })

          const layerName = layerNames[0]

          if (features.length && this.isNeedShowModal) {
            this.layers[layerName] && this.layers[layerName].showModal && this.layers[layerName].showModal(features[0])
          }

          this.$emit('mapClick', {
            features,
            layerNames,
            lng,
            lat,
            local: [lng, lat]
          })
        })
      }

      if (this.isNeedSizeChange) {
        this.Map.getView().on('propertychange', (e) => {
          Utils.isShowOverLayer(this.Map)

          Utils.changeArcgisIcon({
            layers: this.layers
          })

          this.$emit('mapSizeChange', e)
        })
      }

      this.$emit('mapOnLoad', this.Map)
    },
    initActive () {
      if (
        this.isHideBase &&
        this.isHideTerrain &&
        this.isHideSatellite
      ) {
        Commons._showError('必须初始化一个Arcgis图层')
      }

      this.arcgisLayers = []
      this.arcgisIndex = 0

      if (!this.isHideBase) {
        this.layers['baseLayer'] = Maps.baseLayer()
        this.arcgisLayers.push(this.layers['baseLayer'])
        this.arcgisIndex += 1
        this.showIng['baseLayer'] = true
      }

      if (!this.isHideTerrain) {
        this.layers['terrainLayer'] = Maps.terrainLayer()
        this.arcgisLayers.push(this.layers['terrainLayer'])
        this.arcgisIndex += 1
        this.showIng['terrainLayer'] = true
      }

      if (!this.isHideSatellite) {
        this.layers['GdSatelliteLayer'] = Maps.GdSatelliteLayer()
        this.layers['FsSatelliteLayer'] = Maps.FsSatelliteLayer()
        this.arcgisLayers.push(this.layers['GdSatelliteLayer'])
        this.arcgisLayers.push(this.layers['FsSatelliteLayer'])
        this.arcgisIndex += 1
        this.showIng['satelliteLayer'] = true
      }

      if (this.isNeedWaterNet) {
        this.layers['GdWaterNetLayer'] = Maps.GdWaterNetLayer({ layerOptions: { visible: false } })
        this.layers['HnWaterNetLayer'] = Maps.HnWaterNetLayer({ layerOptions: { visible: false } })
        this.arcgisLayers.push(this.layers['GdWaterNetLayer'])
        this.arcgisLayers.push(this.layers['HnWaterNetLayer'])
      }

      if (this.isNeedRoadNet) {
        this.layers['roadNetLayer'] = Maps.roadNetLayer({ layerOptions: { visible: false } })
        this.arcgisLayers.push(this.layers['roadNetLayer'])
      }

      this.layers['FsNhBorderLayer'] = Maps.FsNhBorderLayer()
      this.layers['FsNhTownLayer'] = Maps.FsNhTownLayer()
      this.layers['warnLineLayer'] = Maps.warnLineLayer()

      this.arcgisLayers.push(this.layers['FsNhBorderLayer'])
      this.arcgisLayers.push(this.layers['FsNhTownLayer'])
      this.arcgisLayers.push(this.layers['warnLineLayer'])
      this.showIng['FsNhBorderLayer'] = true
      this.showIng['FsNhTownLayer'] = true
      this.showIng['warnLineLayer'] = true

      switch (this.layerActive) {
        case 'base':
          if (this.isHideBase) {
            Commons._showError('并没有加载普通白底图层，请传入正确的layerActive')
          } else {
            this.layerChosen(this.layerActive, true)
          }
          break
        case 'terrain':
          if (this.isHideTerrain) {
            Commons._showError('并没有加载地形图图层，请传入正确的layerActive')
          } else {
            this.layerChosen(this.layerActive, true)
          }
          break
        case 'satellite':
          if (this.isHideSatellite) {
            Commons._showError('并没有加载卫星图图层，请传入正确的layerActive')
          } else {
            this.layerChosen(this.layerActive, true)
          }
          break
        default:
          Commons._showError('请传入正确的layerActive')
          break
      }
    },
    init () {
      this.initActive()
    }
  }
}
</script>

<style lang="scss" scoped>
  $color-default: #008cee;

  .GykjMap {
    width: 100%;
    height: 100%;
    position: relative;
    overflow: hidden;
    .GykjMap-wrapper {
      width: 100%;
      height: 100%;
      position: absolute;
      top: 0;
      left: 0;
    }
    .GykjMap-chosen {
      z-index: 10;
      position: absolute;
      right: 10px;
      bottom: 10px;
      > .chosen_list {
        height: 66px;
        padding: 8px;
        background-color: rgba(55, 55, 55, .1);
        transition: all .4s;
        user-select: none;
        > .chosen_detail {
          width: 80px;
          height: 50px;
          transition: all .4s;
          border: 1px solid white;
          background-size: 100% 100%;
          position: absolute;
          cursor: pointer;
          &.base {
            background-image: url(./img/maptypeNormal.png);
          }
          &.terrain {
            background-image: url(./img/maptypeEarth.png);
          }
          &.satellite {
            background-image: url(./img/maptypePanorama.png);
          }
          span {
            position: absolute;
            bottom: 0;
            right: 0;
            color: white;
            font-size: 12px;
            transition: all .4s;
          }
          &:hover {
            transform: scale(1.2);
          }
          &:hover, &.active {
            border: 1px solid $color-default;
            span {
              background-color: $color-default;
            }
          }
        }
      }
    }
    .GykjMap-loading {
      width: 100%;
      height: 100%;
      position: absolute;
      top: 0;
      left: 0;
    }
  }
</style>
